using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using RootfusCoreComponents;
using System.Diagnostics;

namespace RoofusUIControls
{
    /// <summary>
    /// This will create a small thumb at the bottom of surface items that are allowed to
    /// be resized. The user can drag that surface item and it will send the correct resizing
    /// instructinos down to SurfaceItem as well as the hosting control.
    /// </summary>
    public class SurfaceItemResizingAdorner : Adorner
    {
        /// <summary>
        /// The bottom right corner is where we are allowed to be used.
        /// </summary>
        Thumb bottomRight;

        /// <summary>
        /// Since we own the thumb, and we have to display it in the adorner layer, we'd better
        /// make it visible to everyone who is going to draw it! :-)
        /// </summary>
        VisualCollection visualChildren;

        /// <summary>
        /// Keep track of the surface item that we are looking at.
        /// </summary>
        FrameworkElement _item = null;

        // Initialize the ResizingAdorner.
        public SurfaceItemResizingAdorner(FrameworkElement item)
            : base(item)
        {
            _item = item;
            visualChildren = new VisualCollection(this);
            Debug.Assert(_item != null, "SurfaceItemResizingAdorner can't deal with a null SurfaceItem!");

            ///
            /// Create the thumb and put it in the visual tree. When the resize
            /// instructions come along, use our special handler.
            ///

            BuildAdornerCorner(ref bottomRight, Cursors.SizeNWSE);
            bottomRight.DragDelta += new DragDeltaEventHandler(HandleBottomRight);
        }

        /// <summary>
        /// The thumb is being used to change the size. Set the item with the new size.
        /// We make an assumption that the reqested size can't get too small.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        void HandleBottomRight(object sender, DragDeltaEventArgs args)
        {
            ///
            /// If the item has NaN as its height or width, fix it to the "desired" size.
            /// 

            EnforceSize(_item);

            ///
            /// args contains how much change their has been. Fix up the element. :-)
            /// 

            double new_width = _item.Width + args.HorizontalChange;
            double new_height = _item.Height + args.VerticalChange;

            if (new_height > _item.MinHeight)
            {
                _item.Height = new_height;
            }
            if (new_width > _item.MinWidth)
            {
                _item.Width = new_width;
            }

            args.Handled = true;
        }


        // Arrange the Adorners.
        protected override Size ArrangeOverride(Size finalSize)
        {
            // desiredWidth and desiredHeight are the width and height of the element that's being adorned.  
            // These will be used to place the ResizingAdorner at the corners of the adorned element.  
            double desiredWidth = AdornedElement.DesiredSize.Width;
            double desiredHeight = AdornedElement.DesiredSize.Height;
            // adornerWidth & adornerHeight are used for placement as well.
            double adornerWidth = this.DesiredSize.Width;
            double adornerHeight = this.DesiredSize.Height;

            //topLeft.Arrange(new Rect(-adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));
            //topRight.Arrange(new Rect(desiredWidth - adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));
            //bottomLeft.Arrange(new Rect(-adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight));
            bottomRight.Arrange(new Rect(desiredWidth - adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight));

            // Return the final size.
            return finalSize;
        }

        // Helper method to instantiate the corner Thumbs, set the Cursor property, 
        // set some appearance properties, and add the elements to the visual tree.
        void BuildAdornerCorner(ref Thumb cornerThumb, Cursor customizedCursor)
        {
            if (cornerThumb != null) return;

            cornerThumb = new Thumb();

            // Set some arbitrary visual characteristics.
            cornerThumb.Cursor = customizedCursor;
            cornerThumb.Height = cornerThumb.Width = 10;
            cornerThumb.Opacity = 0.40;
            cornerThumb.Background = new SolidColorBrush(Colors.MediumBlue);

            visualChildren.Add(cornerThumb);
        }

        /// <summary>
        /// If the item we are resizing usually has its width/height determined by the
        /// size of its contents (not uncommon) we have to do something -- we base our
        /// calculations on the actual size. So, use the Layout engine's desired size to
        /// set the explicit width and height. This does mean that auto-resizing if the
        /// content changes won't happen again. Bummer.
        /// </summary>
        /// <param name="adornedElement"></param>
        void EnforceSize(FrameworkElement adornedElement)
        {
            if (adornedElement.Width.Equals(Double.NaN))
                adornedElement.Width = adornedElement.DesiredSize.Width;
            if (adornedElement.Height.Equals(Double.NaN))
                adornedElement.Height = adornedElement.DesiredSize.Height;

        }

        // Override the VisualChildrenCount and GetVisualChild properties to interface with 
        // the adorner's visual collection.
        protected override int VisualChildrenCount { get { return visualChildren.Count; } }
        protected override Visual GetVisualChild(int index) { return visualChildren[index]; }
    }
}
